home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / dev / cross / devpic.lha / picasm-src / token.c < prev   
C/C++ Source or Header  |  1998-04-19  |  17KB  |  823 lines

  1. /*
  2.  * picasm -- token.c
  3.  *
  4.  * Include handling, macro expansion, lexical analysis
  5.  *
  6.  * Timo Rossi <trossi@iki.fi>
  7.  * 
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <ctype.h>
  14.  
  15. #include "picasm.h"
  16.  
  17. /*
  18.  * keyword table for tokenizer
  19.  *
  20.  * this must be in sync with the token definitions in picasm.h
  21.  */
  22. static char Keyword_Table[] = {
  23.   "include\0"
  24.   "macro\0"
  25.   "endm\0"
  26.   "exitm\0"
  27.   "if\0"
  28.   "else\0"
  29.   "endif\0"
  30.   "equ\0"
  31.   "set\0"
  32.   "end\0"
  33.   "org\0"
  34.   "ds\0"
  35.   "edata\0"
  36.   "config\0"
  37.   "picid\0"
  38.   "device\0"
  39.   "defined\0"
  40.   "streq\0"
  41.   "isstr\0"
  42.   "chrval\0"
  43.   "opt\0"
  44.   "local\0"
  45.   "endlocal\0"
  46.   "error\0"
  47.         
  48. /* 12/14-bit PIC instruction mnemonics */
  49.   "addlw\0"
  50.   "addwf\0"
  51.   "andlw\0"
  52.   "andwf\0"
  53.   "bcf\0"
  54.   "bsf\0"
  55.   "btfsc\0"
  56.   "btfss\0"
  57.   "call\0"
  58.   "clrf\0"
  59.   "clrw\0"
  60.   "clrwdt\0"
  61.   "comf\0"
  62.   "decf\0"
  63.   "decfsz\0"
  64.   "goto\0"
  65.   "incf\0"
  66.   "incfsz\0"
  67.   "iorlw\0"
  68.   "iorwf\0"
  69.   "movlw\0"
  70.   "movf\0"
  71.   "movwf\0"
  72.   "nop\0"
  73.   "option\0"
  74.   "retfie\0"
  75.   "retlw\0"
  76.   "return\0"
  77.   "rlf\0"
  78.   "rrf\0"
  79.   "sleep\0"
  80.   "sublw\0"
  81.   "subwf\0"
  82.   "swapf\0"
  83.   "tris\0"
  84.   "xorlw\0"
  85.   "xorwf\0"
  86.  
  87.   "\0"
  88. };
  89.  
  90. /* tokenizer definitions & variables */
  91. int tok_char;
  92.  
  93. int token_type, line_buf_off;
  94. char token_string[TOKSIZE];
  95. long token_int_val;
  96.  
  97. int ifskip_mode; /* TRUE when skipping code inside if..endif */
  98.  
  99. /*
  100.  * include file handling
  101.  */
  102. void
  103. begin_include(char *fname)
  104. {
  105.   struct inc_file *p;
  106.  
  107.   p = mem_alloc(sizeof(struct inc_file));
  108.   p->type = INC_FILE;
  109.   p->v.f.fname = mem_alloc(strlen(fname)+1);
  110.   strcpy(p->v.f.fname, fname);
  111.   p->linenum = 0;
  112.   p->cond_nest_count = cond_nest_count;
  113.  
  114.   if((p->v.f.fp = fopen(p->v.f.fname, "r")) == NULL) {
  115.     if(current_file == NULL) {
  116.       fatal_error("Can't open '%s'", p->v.f.fname);
  117.     } else {
  118.       error(0, "Can't open include file '%s'", p->v.f.fname);
  119.       free(p->v.f.fname);
  120.       free(p);
  121.       line_buf_ptr = NULL;
  122.       tok_char = ' ';
  123.       return;
  124.     }
  125.   }
  126.  
  127.   p->next = current_file;
  128.   current_file = p;
  129.   line_buf_ptr = NULL;
  130.   tok_char = ' ';
  131. }
  132.  
  133. /*
  134.  * Move to previous level of include/macro
  135.  */
  136. void
  137. end_include(void)
  138. {
  139.   struct inc_file *p;
  140.   struct macro_arg *arg1, *arg2;
  141.  
  142.   if(current_file != NULL) {
  143.     if(cond_nest_count != current_file->cond_nest_count) {
  144.       error(0, "conditional assembly not terminated by ENDIF");
  145.       cond_nest_count = current_file->cond_nest_count;
  146.     }
  147.  
  148.     p = current_file->next;
  149.     if(current_file->type == INC_FILE) {
  150.       fclose(current_file->v.f.fp);
  151.       free(current_file->v.f.fname);
  152.     } else { /* free macro arguments */
  153.       arg1 = current_file->v.m.args;
  154.       while(arg1 != NULL) {
  155.     arg2 = arg1->next;
  156.     free(arg1);
  157.     arg1 = arg2;
  158.       }
  159.     }
  160.     free(current_file);
  161.     current_file = p;
  162.   }
  163. }
  164.  
  165. /*
  166.  * Expand a macro
  167.  */
  168. void
  169. expand_macro(struct symbol *sym)
  170. {
  171.   struct inc_file *minc;
  172.   struct macro_arg *arg;
  173.   char *cp;
  174.   int narg;
  175.   int parcnt, d_char;
  176.  
  177.   write_listing_line(0); /* list the macro call line */
  178.  
  179.   minc = mem_alloc(sizeof(struct inc_file));
  180.   minc->type = INC_MACRO;
  181.   minc->v.m.sym = sym;
  182.   minc->v.m.ml = sym->v.text;
  183.   minc->linenum = 0;
  184.   minc->cond_nest_count = cond_nest_count;
  185.   minc->v.m.args = NULL;
  186.   minc->v.m.uniq_id = unique_id_count++;
  187.   arg = NULL;
  188.  
  189.   for(narg = 1;;narg++) {
  190.     while(tok_char != '\n' && isspace(tok_char)) /* skip whitespace */
  191.       read_src_char();
  192.  
  193.     if(tok_char == '\n' || tok_char == '\0' ||
  194.        tok_char == ';' || tok_char == EOF)
  195.       break;
  196.  
  197.     cp = line_buf_ptr-1;
  198.  
  199.     /*
  200.      * Macro parameters are separated by commas. However, strings and
  201.      * character constants (using double and single quotes)
  202.      * can be used even if they contain commas. Also commas
  203.      * inside parenthesis (such as function parameter delimiters)
  204.      * don't count as macro parameter separators.
  205.      *
  206.      */
  207.  
  208.     parcnt = 0; /* parenthesis nesting count */
  209.  
  210.     while(!isspace(tok_char) &&
  211.       tok_char != '\n' && tok_char != '\0' &&
  212.       tok_char != ';' && tok_char != EOF) {
  213.       if(parcnt == 0 && tok_char == ',')
  214.     break;
  215.  
  216.       if(tok_char == '(') {
  217.     parcnt++;
  218.       } else if(tok_char == ')') {
  219.     parcnt--;
  220.       } else if(tok_char == '"' || tok_char == '\'') {
  221.     /* quoted string or character constant */
  222.     d_char = tok_char;
  223.  
  224.     do {
  225.       read_src_char();
  226.     }
  227.     while(tok_char != d_char && tok_char != '\n' &&
  228.           tok_char != '\0' && tok_char != EOF);
  229.  
  230.     if(tok_char != d_char)
  231.       break;
  232.       }
  233.  
  234.       read_src_char();
  235.     }
  236.  
  237.     if(narg >= 10)
  238.       warning("Too many macro arguments (max. 9)");
  239.  
  240.     if(arg == NULL) {
  241.       arg = mem_alloc(sizeof(struct macro_arg)
  242.               +(line_buf_ptr-cp-1));
  243.       minc->v.m.args = arg;
  244.     } else {
  245.       arg->next = mem_alloc(sizeof(struct macro_arg)
  246.                 +(line_buf_ptr-cp-1));
  247.       arg = arg->next;
  248.     }
  249.     strncpy(arg->text, cp, line_buf_ptr-cp-1);
  250.     arg->text[line_buf_ptr-cp-1] = '\0';
  251.     arg->next = NULL;
  252.  
  253.     /* skip whitespace */
  254.     while(tok_char != '\n' && isspace(tok_char))
  255.       read_src_char();
  256.     if(tok_char != ',')
  257.       break;
  258.  
  259.     read_src_char();
  260.   }
  261.  
  262.   if(tok_char != ';' && tok_char != '\n' &&
  263.      tok_char != '\0' && tok_char != EOF)
  264.     error(0, "Extraneous characters after a valid source line");
  265.  
  266.   minc->next = current_file;
  267.   current_file = minc;
  268.  
  269.   line_buf_ptr = NULL;
  270.   tok_char = ' ';
  271.   get_token();
  272. }
  273.  
  274. /*
  275.  * Read a character from source file.
  276.  * Handles includes and macros.
  277.  */
  278. void
  279. read_src_char(void)
  280. {
  281.   char *scp, *pcp, *dcp;
  282.   int parm;
  283.   struct macro_arg *arg;
  284.   static char tmpbuf[12];
  285.  
  286.   if(line_buf_ptr == NULL || *line_buf_ptr == '\0') {
  287.     if(current_file == NULL) {
  288.       tok_char = EOF;
  289.       return;
  290.     }
  291.  
  292. getc1:
  293.     if(current_file->type == INC_MACRO)    {
  294.       if(current_file->v.m.ml == NULL) {
  295.     end_include();
  296.     goto getc1;
  297.       }
  298.  
  299.       scp = current_file->v.m.ml->text;
  300.       dcp = line_buffer;
  301.       while(*scp != '\0' && dcp < &line_buffer[sizeof(line_buffer)]) {
  302.     if(*scp == '\\') {
  303.       scp++;
  304.       if(*scp >= '1' && *scp <= '9') { /* macro arg */
  305.         parm = *scp - '1'; /* macro arg #, starting from 0 */
  306.         for(arg = current_file->v.m.args;
  307.         arg != NULL && parm > 0; arg = arg->next, parm--);
  308.         if(arg != NULL) {
  309.           for(pcp = arg->text; *pcp != '\0' &&
  310.           dcp < &line_buffer[sizeof(line_buffer)];)
  311.         *dcp++ = *pcp++;
  312.         }
  313.         scp++;
  314.       } else if(*scp == '0' || *scp == '@') {
  315.         sprintf(tmpbuf, "%03d", current_file->v.m.uniq_id);
  316.  
  317.         for(pcp = tmpbuf; *pcp != '\0' &&
  318.         dcp < &line_buffer[sizeof(line_buffer)];)
  319.           *dcp++ = *pcp++;
  320.  
  321.         scp++;
  322.       } else if(*scp == '#') { /* number of arguments */
  323.         for(parm = 0, arg = current_file->v.m.args;
  324.         arg != NULL; arg = arg->next, parm++);
  325.  
  326.         sprintf(tmpbuf, "%d", parm);
  327.  
  328.         for(pcp = tmpbuf; *pcp != '\0' &&
  329.         dcp < &line_buffer[sizeof(line_buffer)];)
  330.           *dcp++ = *pcp++;
  331.  
  332.         scp++;
  333.       } else
  334.         *dcp++ = *scp;
  335.     } else
  336.       *dcp++ = *scp++;
  337.       }
  338.       if(dcp == &line_buffer[sizeof(line_buffer)]) {
  339.     error(0, "Line buffer overflow");
  340.     dcp--;
  341.       }
  342.  
  343.       *dcp = '\0'; /* NUL-terminate the line */
  344.       current_file->v.m.ml = current_file->v.m.ml->next;
  345.     } else {
  346.       if(fgets(line_buffer, sizeof(line_buffer)-1,
  347.            current_file->v.f.fp) == NULL) {
  348.     if(current_file->next != NULL) {
  349.       end_include();
  350.       goto getc1;
  351.     }
  352.     tok_char = EOF;
  353.     return;
  354.       }
  355.     }
  356.     current_file->linenum++;
  357.     line_buf_ptr = line_buffer;
  358.   }
  359.   tok_char = ((unsigned char)(*line_buf_ptr++));
  360. }
  361.  
  362. /*
  363.  * Lexical analyzer
  364.  * Returns the next token from the source file
  365.  */
  366. void
  367. get_token(void)
  368. {
  369.   int tp, base;
  370.   char *cp;
  371.  
  372.   for(;;) {
  373.     /*
  374.      * skip spaces
  375.      */
  376.     while(tok_char != '\n' && isspace(tok_char))
  377.       read_src_char();
  378.  
  379.     if(tok_char == EOF)    {
  380.       token_type = TOK_EOF;
  381.       token_string[0] = '\0';
  382.       return;
  383.     }
  384.  
  385.     if(tok_char != ';')
  386.       break;
  387.  
  388.     /* comment */
  389.     line_buf_ptr = NULL;
  390.     tok_char = '\n';
  391.  
  392.   } /* for(;;) */
  393.  
  394. /*
  395.  * character constant (integer)
  396.  * (does not currently handle the quote character)
  397.  */
  398.   if(tok_char == '\'') {
  399.     read_src_char();
  400.     token_string[0] = tok_char;
  401.     read_src_char();
  402.     if(tok_char != '\'')
  403.       goto invalid_token;
  404.     read_src_char();
  405.     token_string[1] = '\0';
  406.     token_int_val = (long)((unsigned char)token_string[0]);
  407.     token_type = TOK_INTCONST;
  408.     return;
  409.   }
  410.  
  411.   if(tok_char == '"') { /* string constant (include filename) */
  412.     read_src_char();
  413.     tp = 0;
  414.     while(tp < TOKSIZE-1 && tok_char != '"' && tok_char != EOF)    {
  415.       token_string[tp++] = tok_char;
  416.       read_src_char();
  417.     }
  418.     if(tok_char != '\"' && !ifskip_mode)
  419.       error(0, "String not terminated");
  420.     token_string[tp] = '\0';
  421.     read_src_char();
  422.     token_type = TOK_STRCONST;
  423.     return;
  424.   }
  425.  
  426. /*
  427.  * integer number
  428.  */
  429.   if(isdigit(tok_char)) {
  430.     token_type = TOK_INTCONST;
  431.     token_string[0] = tok_char;
  432.     tp = 1;
  433.     read_src_char();
  434.     if(token_string[0] == '0') {
  435.       if(tok_char == 'x' || tok_char == 'X') { /* hex number */
  436.     token_string[tp++] = tok_char;
  437.     read_src_char();
  438.     while(tp < TOKSIZE-1 && isxdigit(tok_char)) {
  439.       token_string[tp++] = tok_char;
  440.       read_src_char();
  441.     }
  442.     token_string[tp] = '\0';
  443.     token_int_val = strtoul(&token_string[2], NULL, 16);
  444.     /* should put range check here */
  445.     return;
  446.       }
  447.     }
  448.  
  449.     while(tp < TOKSIZE-2 && isxdigit(tok_char))    {
  450.       token_string[tp++] = tok_char;
  451.       read_src_char();
  452.     }
  453.  
  454.     base = 10;
  455.     switch(tok_char) {
  456.       case 'H': /* hex */
  457.       case 'h':
  458.         base = 16; /* hex */
  459.     token_string[tp++] = tok_char;
  460.     read_src_char();
  461.     break;
  462.  
  463.       case 'O': /* octal */
  464.       case 'o':
  465.     base = 8; /* octal */
  466.     token_string[tp++] = tok_char;
  467.     read_src_char();
  468.     break;
  469.  
  470.       default:
  471.     if(token_string[0] == '0' &&
  472.        (token_string[1] == 'b' || token_string[1] == 'B')) {
  473.       token_string[tp] = '\0';
  474.       token_int_val = strtoul(&token_string[2], &cp, 2);
  475.       if(cp != &token_string[tp] && !ifskip_mode)
  476.         error(0, "Invalid digit in a number");
  477.       /* should put range check here */
  478.       return;
  479.     } else if(token_string[tp-1] == 'B' || token_string[tp-1] == 'b') {
  480.       base = 2;
  481.     } else {
  482.       if(token_string[tp-1] != 'D' && token_string[tp-1] != 'd')
  483.         token_string[tp++] = '\0';
  484.     }
  485.     break;
  486.     }
  487.  
  488.     token_string[tp] = '\0';
  489.     token_int_val = strtoul(token_string, &cp, base);
  490.     if(cp != &token_string[tp-1] && !ifskip_mode)
  491.       error(0, "Invalid digit in a number");
  492.     /* should put range check here */
  493.     return;
  494.   }
  495.  
  496. /*
  497.  * Handle B'10010100' binary etc.
  498.  */
  499.   if((tok_char == 'b' || tok_char == 'B' ||
  500.       tok_char == 'd' || tok_char == 'D' ||
  501.       tok_char == 'h' || tok_char == 'H' ||
  502.       tok_char == 'o' || tok_char == 'O') &&
  503.      line_buf_ptr != NULL && *line_buf_ptr == '\'') {
  504.     token_string[0] = tok_char;
  505.     read_src_char();
  506.     token_string[1] = tok_char;
  507.     read_src_char();
  508.     tp = 2;
  509.     while(tp < TOKSIZE-1 && isxdigit(tok_char))    {
  510.       token_string[tp++] = tok_char;
  511.       read_src_char();
  512.     }
  513.     if(tok_char != '\'')
  514.       goto invalid_token;
  515.     token_string[tp++] = tok_char;
  516.     read_src_char();
  517.     token_string[tp] = '\0';
  518.  
  519.     switch(token_string[0]) {
  520.       case 'b':
  521.       case 'B':
  522.         base = 2;
  523.     break;
  524.  
  525.       case 'o':
  526.       case 'O':
  527.     base = 8;
  528.     break;
  529.  
  530.       case 'h':
  531.       case 'H':
  532.     base = 16;
  533.     break;
  534.  
  535.       case 'd':
  536.       case 'D':
  537.       default:
  538.     base = 10;
  539.     break;
  540.     }
  541.  
  542.     token_int_val = strtoul(&token_string[2], &cp, base);
  543.     if(cp != &token_string[tp-1] && !ifskip_mode)
  544.       error(0, "Invalid digit in a number");
  545.     /* should put range check here */
  546.     token_type = TOK_INTCONST;
  547.     return;
  548.   }
  549.  
  550. /*
  551.  * keyword or identifier
  552.  */
  553.   if(tok_char == '_' || tok_char == '.' || isalpha(tok_char)) {
  554.     line_buf_off = (line_buf_ptr - &line_buffer[1]);
  555.  
  556.     token_string[0] = tok_char;
  557.     tp = 1;
  558.     read_src_char();
  559.  
  560.     if(token_string[0] == '.' &&
  561.        tok_char != '_' && !isalnum(tok_char)) {
  562.       token_string[1] = '\0';
  563.       token_type = TOK_PERIOD;
  564.       return;
  565.     }
  566.  
  567.     while(tp < TOKSIZE-1 &&
  568.       (tok_char == '_' || tok_char == '.' || isalnum(tok_char))) {
  569.       token_string[tp++] = tok_char;
  570.       read_src_char();
  571.     }
  572.     token_string[tp] = '\0';
  573.  
  574.     token_type = FIRST_KW;
  575.     cp = Keyword_Table;
  576.     while(*cp) {
  577.       if(strcasecmp(token_string, cp) == 0)
  578.     return;
  579.       while(*cp++)
  580.     ;
  581.       token_type++;
  582.     }
  583.     token_type = TOK_IDENTIFIER;
  584.     return;
  585.   }
  586.  
  587. /*
  588.  * non-numeric & non-alpha tokens
  589.  */
  590.   switch(tok_char) {
  591.     case '\n':
  592.     case '\0':
  593.       token_type = TOK_NEWLINE;
  594.       strcpy(token_string, "\\n");
  595.       skip_eol();
  596.       return;
  597.  
  598.     case '<':
  599.       token_string[0] = tok_char;
  600.       read_src_char();
  601.       if(tok_char == '<') {
  602.     token_string[1] = tok_char;
  603.     token_string[2] = '\0';
  604.     token_type = TOK_LSHIFT;
  605.     read_src_char();
  606.     return;
  607.       }
  608.  
  609.       if(tok_char == '=') {
  610.     token_string[1] = tok_char;
  611.     token_string[2] = '\0';
  612.     token_type = TOK_LESS_EQ;
  613.     read_src_char();
  614.     return;
  615.       }
  616.  
  617.       if(tok_char == '>') {
  618.     token_string[1] = tok_char;
  619.     token_string[2] = '\0';
  620.     token_type = TOK_NOT_EQ;
  621.     read_src_char();
  622.     return;
  623.       }
  624.  
  625.       token_type = TOK_LESS;
  626.       token_string[1] = '\0';
  627.       return;
  628.  
  629.     case '>':
  630.       token_string[0] = tok_char;
  631.       read_src_char();
  632.       if(tok_char == '>') {
  633.     token_string[1] = tok_char;
  634.     token_string[2] = '\0';
  635.     token_type = TOK_RSHIFT;
  636.     read_src_char();
  637.     return;
  638.       }
  639.  
  640.       if(tok_char == '=') {
  641.     token_string[1] = tok_char;
  642.     token_string[2] = '\0';
  643.     token_type = TOK_GT_EQ;
  644.     read_src_char();
  645.     return;
  646.       }
  647.  
  648.       token_string[1] = '\0';
  649.       token_type = TOK_GREATER;
  650.       return;
  651.  
  652.     case '!':
  653.       token_string[0] = tok_char;
  654.       read_src_char();
  655.       if(tok_char != '=')
  656.     goto invalid_token;
  657.       token_string[1] = tok_char;
  658.       token_string[2] = '\0';
  659.       read_src_char();
  660.       token_type = TOK_NOT_EQ;
  661.       return;
  662.  
  663.     case '=':
  664.       token_string[0] = tok_char;
  665.       read_src_char();
  666.       if(tok_char == '=') {
  667.     token_string[1] = tok_char;
  668.     read_src_char();
  669.     token_string[2] = '\0';
  670.     token_type = TOK_EQ;
  671.     return;
  672.       }
  673.  
  674.       if(tok_char == '<') {
  675.     token_string[1] = tok_char;
  676.     read_src_char();
  677.     token_string[2] = '\0';
  678.     token_type = TOK_LESS_EQ;
  679.     return;
  680.       }
  681.  
  682.       if(tok_char == '>') {
  683.     token_string[1] = tok_char;
  684.     read_src_char();
  685.     token_string[2] = '\0';
  686.     token_type = TOK_GT_EQ;
  687.     return;
  688.       }
  689.  
  690.       if(tok_char == '_' || tok_char == '.' ||
  691.      isalpha(tok_char)) { /* local symbol */
  692.     line_buf_off = (line_buf_ptr - &line_buffer[2]);
  693.  
  694.     token_string[0] = tok_char;
  695.     tp = 1;
  696.     read_src_char();
  697.  
  698.     while(tp < TOKSIZE-1 &&
  699.           (tok_char == '_' || tok_char == '.' || isalnum(tok_char))) {
  700.       token_string[tp++] = tok_char;
  701.       read_src_char();
  702.     }
  703.     token_string[tp] = '\0';
  704.  
  705.     token_type = TOK_LOCAL_ID;
  706.     return;
  707.       }
  708.  
  709.       token_string[1] = '\0';
  710.       token_type = TOK_EQUAL;
  711.       return;
  712.  
  713.     case '$':
  714.       read_src_char();
  715.       if(!isxdigit(tok_char))
  716.     {
  717.       token_string[0] = '$';
  718.       token_string[1] = '\0';
  719.       token_type = TOK_DOLLAR;
  720.       return;
  721.     }
  722.  
  723.       tp = 0;
  724.       do
  725.     {
  726.       token_string[tp++] = tok_char;
  727.       read_src_char();
  728.     } while(tp < TOKSIZE-1 && isxdigit(tok_char));
  729.  
  730.       token_string[tp] = '\0';
  731.       token_int_val = strtoul(&token_string[1], NULL, 16);
  732.       token_type = TOK_INTCONST;
  733.       /* should put range check here */
  734.       return;
  735.  
  736.     case '\\':
  737.       token_type = TOK_BACKSLASH;
  738.       break;
  739.  
  740.     case ',':
  741.       token_type = TOK_COMMA;
  742.       break;
  743.  
  744.     case '(':
  745.       token_type = TOK_LEFTPAR;
  746.       break;
  747.  
  748.     case ')':
  749.       token_type = TOK_RIGHTPAR;
  750.       break;
  751.  
  752.     case '+':
  753.       token_type = TOK_PLUS;
  754.       break;
  755.  
  756.     case '-':
  757.       token_type = TOK_MINUS;
  758.       break;
  759.  
  760.     case '&':
  761.       token_type = TOK_BITAND;
  762.       break;
  763.  
  764.     case '|':
  765.       token_type = TOK_BITOR;
  766.       break;
  767.  
  768.     case '^':
  769.       token_type = TOK_BITXOR;
  770.       break;
  771.  
  772.     case '~':
  773.       token_type = TOK_BITNOT;
  774.       break;
  775.  
  776.     case '*':
  777.       token_type = TOK_ASTERISK;
  778.       break;
  779.  
  780.     case '/':
  781.       token_type = TOK_SLASH;
  782.       break;
  783.  
  784.     case '%':
  785.       token_type = TOK_PERCENT;
  786.       break;
  787.  
  788.     case ':':
  789.       token_type = TOK_COLON;
  790.       break;
  791.  
  792.     case '[':
  793.       token_type = TOK_LEFTBRAK;
  794.       break;
  795.  
  796.     case ']':
  797.       token_type = TOK_RIGHTBRAK;
  798.       break;
  799.  
  800.     default:
  801.       goto invalid_token;
  802.   }
  803.  
  804.   token_string[0] = tok_char;
  805.   token_string[1] = '\0';
  806.   read_src_char();
  807.   return;
  808.  
  809. invalid_token:
  810.   if(!ifskip_mode)
  811.     error(0, "Invalid token");
  812.   token_string[0] = '\0';
  813.   token_type = TOK_INVALID;
  814. }
  815.  
  816. /* skip to the next line */
  817. void
  818. skip_eol(void)
  819. {
  820.   line_buf_ptr = NULL;
  821.   tok_char = ' ';
  822. }
  823.